home *** CD-ROM | disk | FTP | other *** search
- STI ;Allow interrupts
- ;
- PUSH AX ;Save registers
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DS
- PUSH SI
- PUSH ES
- PUSH DI
- ;
- ; Get data segment for addressing global variables
- ;
- CS: MOV DS,[>Async_DSeg_Save]
- ;
- ; Begin major polling loop over pending interrupts.
- ;
- ; The polling loop is needed because the 8259 cannot handle another 8250
- ; interrupt while we service this interrupt. We keep polling here as long
- ; as an interrupt is received.
- ;
- Poll: MOV DX,[>Async_Uart_IIR] ;Get Interrupt ident register
- IN AL,DX ;Pick up interrupt type
- ;
- TEST AL,1 ;See if any interrupt signalled.
- JZ Polla ;Yes --- continue
- JMP NEAR Back ;No --- return to invoker
- ;
- ; Determine type of interrupt.
- ; Possibilities:
- ;
- ; 0 = Modem status changed
- ; 2 = Transmit hold register empty (write char)
- ; 4 = Character received from port
- ; 6 = Line status changed
- ;
- Polla: AND AL,6 ;Strip unwanted bits from interrupt type
- CMP AL,4 ;Check if interrupt >= 4
- JE Pollb ;
- JMP NEAR Int2
- ;
- ; Write interrupts must be turned on if a higher-priority interrupt
- ; has been received, else the characters may not be sent (and a lockup
- ; may occur).
- ;
- Pollb: PUSH AX ;Save interrupt type
- CALL EnabWI ;Enable write interrupts
- POP AX ;Restore interrupt type
- ;
- ; --- Received a character ----
- ;
- Int4: CMP AL,4 ;Check for received char interrupt
- JE Int4a ;Yes -- process it.
- JMP NEAR Int2 ;No -- skip.
- ;
- ; Read the character from the serial port.
- ;
- Int4a: MOV DX,[>Async_Base] ;Read character from port
- IN AL,DX
- ;
- ; Check if XON/XOFF honored. If so, check if incoming character is
- ; an XON or an XOFF.
- ;
- TEST BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF
- JZ Int4d ;No -- skip XON/XOFF checks
- ;
- CMP AL,<XON ;See if XON found
- JE Int4b ;Skip if XON found
- CMP AL,<XOFF ;See if XOFF found
- JNE Int4d ;Skip if XOFF not found
- ;
- ; XOFF received -- set flag indicating sending of chars isn't possible
- ;
- MOV BYTE [<Async_XOFF_Received],1 ;Turn on received XOFF flag
- MOV BYTE [<Async_XOFF_Rec_Display],1 ;Turn on display flag
- JMP NEAR Poll
- ;
- ; XON received -- allow more characters to be sent.
- ;
- Int4b: MOV BYTE [<Async_XOFF_Received],0 ;Turn off received XOFF flag
- MOV BYTE [<Async_XON_Rec_Display],1 ;Turn on display flag
- ;
- CALL EnabWI ;Enable write interrupts
- JMP NEAR Int4z
- ;
- ; Not XON/XOFF -- handle other character.
- ;
- Int4d: TEST BYTE [>Async_Line_Status],2 ;Check for buffer overrun
- JNZ Int4z ;Yes --- don't store anything
- ;
- MOV BX,[>Async_Buffer_Head] ;Current position in input buffer
- LES DI,[>Async_Buffer_Ptr] ;Pick up buffer address
- ADD DI,BX ;Update position
- ES: MOV [DI],AL ;Store received character in buffer
- INC WORD [>Async_Buffer_Used] ;Increment count of chars in buffer
- ;
- MOV AX,[>Async_Buffer_Used] ;Pick up buffer usage count
- CMP AX,[>Async_MaxBufferUsed] ;See if greater usage than ever before
- JLE Int4f ;Skip if not
- MOV [>Async_MaxBufferUsed],AX ;This is greatest use thus far
- ;
- Int4f: INC BX ;Increment buffer pointer
- CMP BX,[>Async_Buffer_Size] ;Check if past end of buffer
- JLE Int4h
- XOR BX,BX ;If so, wrap around to front
- ;
- Int4h: CMP WORD [>Async_Buffer_Tail],BX ;Check for overflow
- JE Int4s ;Jump if head ran into tail
- ;
- MOV [>Async_Buffer_Head],BX ;Update head pointer
- ;
- ; If XON/XOFF available, and buffer getting full, set up to send
- ; XOFF to remote system.
- ;
- ; This happens in two possible stages:
- ;
- ; (1) An XOFF is sent right when the buffer becomes 'Async_Buffer_High'
- ; characters full.
- ;
- ; (2) A second XOFF is sent right when the buffer becomes
- ; 'Async_Buffer_High_2' characters full; this case is likely the
- ; result of the remote not having seen our XOFF because it was
- ; lost in transmission.
- ;
- TEST BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF
- JZ Int4z ;No -- skip XON/XOFF checks
- ;
- ; Check against first high-water mark.
- ;
- CMP AX,[>Async_Buffer_High] ;AX still has Async_Buffer_Used
- JL Int4z ;Not very full, so keep going.
- ;
- ; Check if we've already sent XOFF.
- ;
- TEST BYTE [<Async_XOFF_Sent],1 ;Remember if we sent XOFF or not
- JZ Int4j ;No -- go send it now.
- ;
- ; Check against second high-water mark.
- ; If we are right at it, send an XOFF regardless of whether we've
- ; already sent one or not. (Perhaps the first got lost.)
- ;
- CMP AX,[>Async_Buffer_High_2]
- JNE Int4z ;Not at 2nd mark -- skip
- ;
- Int4j: MOV BYTE [<Async_Send_XOFF],1 ;Indicate we need to send XOFF
- CALL EnabWI ;Ensure write interrupts enabled
- JMP NEAR Poll ;
- ;
- ; If we come here, then the input buffer has overflowed.
- ; Characters will be thrown away until the buffer empties at least one slot.
- ;
- Int4s: OR BYTE PTR [>Async_Line_Status],2 ;Flag overrun
- ;
- Int4z: JMP NEAR Poll
- ;
- ; --- Write a character ---
- ;
- Int2: CMP AL,2 ;Check for THRE interrupt
- JE Int2a ;Yes -- process it.
- JMP NEAR Int6 ;No -- skip.
- ;
- ; Check first if we need to send an XOFF to remote system.
- ;
- Int2a: TEST BYTE [<Async_Send_Xoff],1 ;See if we are sending XOFF
- JZ Int2d ;No -- skip it
- ;
- ; Yes, we are to send XOFF to remote.
- ;
- ; First, check DSR and CTS as requested.
- ; If those status lines aren't ready, turn off write interrupts and
- ; try later, after a line status change.
- ;
- TEST BYTE [<Async_Do_DSR],1 ;See if DSR checking required
- JZ Int2b ;No -- skip it
- ;
- MOV DX,[>Async_Uart_MSR] ;Get modem status register
- IN AL,DX
- TEST AL,<Async_DSR ;Check for Data Set Ready
- JZ Int2e ;If not DSR, turn off write interrupts
- ;
- Int2b: TEST BYTE [<Async_Do_CTS],1 ;See if CTS checking required
- JZ Int2c ;No -- skip it
- ;
- MOV DX,[>Async_Uart_MSR] ;Get modem status register
- IN AL,DX
- TEST AL,<Async_CTS ;Check for Clear To Send
- JZ Int2e ;If not CTS, turn off write ints
- ;
- ; All status lines look OK.
- ; Send the XOFF.
- ;
- Int2c: MOV AL,<XOFF ;Get XOFF Character
- MOV DX,[>Async_Base] ;Get transmit hold register address
- OUT DX,AL ;Output the XOFF
- MOV BYTE [<Async_Send_XOFF],0 ;Turn off send XOFF flag
- MOV BYTE [<Async_XOFF_Sent],1 ;Turn on sent XOFF flag
- JMP NEAR Poll ;Return
- ;
- ; Not sending XOFF -- see if any character in buffer to be sent.
- ;
- Int2d: MOV BX,[>Async_OBuffer_Tail] ;Pick up output buffer pointers
- CMP BX,[>Async_OBuffer_Head]
- JNE Int2m ;Skip if not equal --> something to send
- ;
- ; If nothing to send, turn off write interrupts to avoid unnecessary
- ; time spent handling useless THRE interrupts.
- ;
- Int2e: MOV DX,[>Async_Uart_IER] ;If nothing -- or can't -- send ...
- IN AL,DX ;
- AND AL,$FD ;
- OUT DX,AL ;... disable write interrupts
- JMP NEAR Poll ;
- ;
- ; If something to send, ensure that remote system didn't send us XOFF.
- ; If it did, we can't send anything, so turn off write interrupts and
- ; wait for later (after an XON has been received).
- ;
- Int2m: TEST BYTE [<Async_XOFF_Received],1 ;See if we received XOFF
- JNZ Int2e ;Yes -- can't send anything now
- ;
- ; If we can send character, check DSR and CTS as requested.
- ; If those status lines aren't ready, turn off write interrupts and
- ; try later, after a line status change.
- ;
- MOV DX,[>Async_Uart_MSR] ;Otherwise get modem status
- IN AL,DX
- MOV [>Async_Modem_Status],AL ;and save modem status for later
- ;
- TEST BYTE [<Async_Do_DSR],1 ;See if DSR checking required
- JZ Int2n ;No -- skip it
- ;
- TEST AL,<Async_DSR ;Check for Data Set Ready
- JZ Int2e ;If not DSR, turn off write ints
- ;
- Int2n: TEST BYTE [<Async_Do_CTS],1 ;See if CTS checking required
- JZ Int2o ;No -- skip it
- ;
- TEST AL,<Async_CTS ;Check for Clear To Send
- JZ Int2e ;If not CTS, turn off write ints
- ;
- ; Everything looks OK for sending, so send the character.
- ;
- Int2o: LES DI,[>Async_OBuffer_Ptr] ;Get output buffer pointer
- ADD DI,BX ;Position to character to output
- ES: MOV AL,[DI] ;Get character to output
- MOV DX,[>Async_Base] ;Get transmit hold register address
- OUT DX,AL ;Output the character
- ;
- DEC WORD [>Async_OBuffer_Used] ;Decrement count of chars in buffer
- INC BX ;Increment tail pointer
- CMP BX,[>Async_OBuffer_Size] ;See if past end of buffer
- JLE Int2z
- XOR BX,BX ;If so, wrap to front
- ;
- Int2z: MOV [>Async_OBuffer_Tail],BX ;Store updated buffer tail
- JMP NEAR Poll
- ;
- ; --- Line status change ---
- ;
- Int6: CMP AL,6 ;Check for line status interrupt
- JNE Int0 ;No -- skip.
- ;
- MOV DX,[>Async_Uart_LSR] ;Yes -- pick up line status register
- IN AL,DX ;and its contents
- AND AL,$1E ;Strip unwanted bits
- MOV [>Async_Line_Status],AL ;Store for future reference
- OR [>Async_Line_Error_Flags],AL ;Add to any past transgressions
- JMP NEAR Poll
- ;
- ; --- Modem status change ---
- ;
- Int0: CMP AL,0 ;Check for modem status change
- JE Int0a ;Yes -- handle it
- JMP NEAR Poll ;Else get next interrupt
- ;
- Int0a: MOV DX,[>Async_Uart_MSR] ;Pick up modem status reg. address
- IN AL,DX ;and its contents
- MOV [>Async_Modem_Status],AL ;Store for future reference
- CALL EnabWI ;Turn on write interrupts, in case
- ; ;status change resulted from CTS/DSR
- ; ;changing state.
- JMP NEAR Poll
- ;
- ; Internal subroutine to enable write interrupts.
- ;
- EnabWI: ;PROC NEAR
- MOV DX,[>Async_Uart_IER] ;Get interrupt enable register
- IN AL,DX ;Check contents of IER
- TEST AL,2 ;See if write interrupt enabled
- JNZ EnabRet ;Skip if so
- OR AL,2 ;Else enable write interrupts ...
- OUT DX,AL ;... by rewriting IER contents
- EnabRet: RET ;Return to caller
- ;
- ; Send non-specific EOI to 8259 controller.
- ;
- Back: MOV AL,$20 ;EOI = $20
- OUT $20,AL
- ;
- ; Restore registers
- ;
- POP DI
- POP ES
- POP SI
- POP DS
- POP DX
- POP CX
- POP BX
- POP AX
- MOV SP,BP
- POP BP
- IRET